package com.app.config;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCachePrefix;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

import com.app.util.StringUtil;

import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Protocol;

/**
 * 类描述： springboot-redis缓存配置类
 * 
 *    @EnableCaching 注解开启缓存，Redis将作为springboot项目默认的全局缓存，支持使用
 *                    @Cacheable,@Cacheput,@CacheEvict注解来存储、移除缓存
 *    @Configuration 通知spring 此类为配置类
 *    @propertySource 指定读取redisConfig.properties 配置文件
 *    
 *    
 * 创建者： shen_hy
 * 项目名称： webapp
 * 创建时间： 2018年4月14日 下午5:02:58
 * 版本号： v1.0
 */
@Configuration
@EnableCaching
@PropertySource("classpath:/redisConfig.properties")
public class RedisAppConfig extends CachingConfigurerSupport{
	
	@Value("${spring.redis.pool.min-idle}")
	private String minIdl;
	
	@Value("${spring.redis.pool.max-idle}")
	private String maxIdl;
	
	@Value("${spring.redis.pool.max-active}")
	private String maxActive;
	
	@Value("${spring.redis.pool.max-wait}")
	private String maxWait;	
	
	@Value("${spring.redis.database}")
	private String database;
	
	@Value("${spring.redis.host}")
	private String host;
	
	@Value("${spring.redis.port}")
	private String port;
	
	@Value("${spring.redis.password}")
	private String password;
	
	@Value("${spring.redis.timeout}")
	private String timeOut;
	
	@Value("${redis.cacheNames}")
	private String cacheNames;

	
    /**
     * 方法描述 : redis缓存模板
     *         可配置连接工厂，key,value序列化方法
     * 创建者：shen_hy 
     * 项目名称： webapp
     * 类名： RedisAppConfig.java
     * 版本： v1.0
     * 创建时间： 2018年4月14日 下午5:16:28
     * @return RedisTemplate<?,?>
     */
    @Bean
	public RedisTemplate<?,?> redisTemplate(){
    	  	
    	RedisTemplate<?,?> template  = new RedisTemplate<>();
    	template.setConnectionFactory(jedisConnectionFactory());

    	// 默认使用 JdkSerializationRedisSerializer
//    	template.setKeySerializer(new Jackson2JsonRedisSerializer<>(Object.class));
//    	template.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
    	template.afterPropertiesSet();
		return template;
	}
    
    /**
     * 方法描述 :指定 RedisCacheManager为缓存管理类
     * 创建者：shen_hy 
     * 项目名称： webapp
     * 类名： RedisAppConfig.java
     * 版本： v1.0
     * 创建时间： 2018年4月14日 下午5:16:28
     * @return CacheManager
     */
	@Bean
	public CacheManager cacheManager() {
				
		RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate());	
		// 初始化几个缓存名称
		Set<String> cacheNameSet = new HashSet<String>();
		// 缓存存活时间
		Map<String,Long> expires = new HashMap<String,Long>();
		
		// 配置文件中指定了服务启动之初，需要创建的几个缓存
		if(!StringUtil.isEmpty(cacheNames)){
			// 根据逗号分隔不同的缓存名字
			String[] nameAndExpireArray = cacheNames.split(",");
			int len = nameAndExpireArray.length;
			for(int i = 0 ; i < len ; i++ ){
				String nameAndExpire = nameAndExpireArray[i];
				String[] array = nameAndExpire.split(":");
				// 缓存名字
				String name = "" ;
				// 缓存存活时间
				long expire = 0 ;
				if(!StringUtil.isEmpty(array[0])){
					name = array[0];
					if(!StringUtil.isEmpty(array[1])){
						expire = Long.parseLong(array[1]);
					}else{
						// 没设置的话默认半小时
						expire = 1800;
					}
					// 增加缓存名字
					cacheNameSet.add(name);
					// 为名称为name的缓存设置缓存存活时间，以秒为单位
					expires.put(name, expire);
				}
			}
		}
		
		cacheManager.setExpires(expires);
		cacheManager.setCacheNames(cacheNameSet);
		cacheManager.setUsePrefix(true);		
		cacheManager.setCachePrefix(redisCachePrefix());
		
		return cacheManager;
	}

	@Override
	public CacheResolver cacheResolver() {
		// TODO Auto-generated method stub
		return super.cacheResolver();
	}

	@Override
	public CacheErrorHandler errorHandler() {
		// TODO Auto-generated method stub
		return super.errorHandler();
	}

	@Override
	public KeyGenerator keyGenerator() {
		// TODO Auto-generated method stub
		return super.keyGenerator();
	}


     
    /**
     * 方法描述 : 创建连接工厂
     * 创建者：shen_hy 
     * 项目名称： webapp
     * 类名： RedisAppConfig.java
     * 版本： v1.0
     * 创建时间： 2018年4月14日 下午5:14:07
     * @return JedisConnectionFactory
     */
    @Bean
    public JedisConnectionFactory jedisConnectionFactory(){
    	
    	JedisConnectionFactory factory = new JedisConnectionFactory(jedisPoolConfig());
    	
    	int redisPort = StringUtil.isEmpty(port)? Protocol.DEFAULT_PORT : Integer.parseInt(port) ;
    	int redisTimeOut = StringUtil.isEmpty(timeOut)? Protocol.DEFAULT_TIMEOUT : Integer.parseInt(timeOut);
    	int redisDataBase = StringUtil.isEmpty(database)?Protocol.DEFAULT_DATABASE:Integer.parseInt(database);
    	factory.setPassword(password);
    	factory.setHostName(host);
    	factory.setPort(redisPort);
    	factory.setTimeout(redisTimeOut);
    	factory.setDatabase(redisDataBase);
    	
    	return factory;
    }
    
	/**
	 * 方法描述 : 创建管理程序访问redis服务器的连接池
	 * 创建者：shen_hy 
	 * 项目名称： webapp
	 * 类名： RedisAppConfig.java
	 * 版本： v1.0
	 * 创建时间： 2018年4月14日 下午5:12:40
	 * @return JedisPoolConfig
	 */
	@Bean
	public JedisPoolConfig jedisPoolConfig(){
			
		JedisPoolConfig poolConfig = new JedisPoolConfig();		
		poolConfig.setMaxIdle(0);
		poolConfig.setMaxTotal(18000);
		poolConfig.setMinIdle(0);
		poolConfig.setMaxWaitMillis(10000);		
		
		return poolConfig;
	}
	
	public RedisCachePrefix redisCachePrefix(){
		return new CachePrefixConfig();
	}

}
